///@file FMErrorLog.cpp
/// <summary>
///   
/// </summary>
/// -------------------------------------------------------------------------<BR>
/// <description>
/// <BR>
/// </description>
/// <BR>
/// Created By: ypwang<BR>
/// Creation Date: Thursday April 19, 2012 <BR>  
/// Reviewed By: <BR>
/// Review Date: <BR>
/// -------------------------------------------------------------------------<BR>

#include "StdAfx.h"
#include "ErrorLog.h"
//#include "FMCrashRpt.h"
//#include "..\Main.win\BuildNum.h"
//#include "..\include\ver_fm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define INFO_BUFFER_SIZE 32767
CFMErrorLog* CFMErrorLog::m_pInstance=NULL;
#define FM_ERROR_LOG_FOLDER  _T("FMErrorLog")
static BOOL m_bShowDefaultInfo = TRUE; 

CFMErrorLog::CFMErrorLog()
{
	GetAssertLevel();
}

CFMErrorLog* CFMErrorLog::GetInstance()
{
	if (NULL==m_pInstance)
	{
		m_pInstance = new CFMErrorLog;
	}
	return m_pInstance;
}

void CFMErrorLog::ReleaseInstance()
{
	if(m_pInstance != NULL)
	{
		delete m_pInstance;
		m_pInstance = NULL;
	}
}

CString CFMErrorLog::FMGetCurrentDirFile(int iErrorType ) 
{
	CString strCurrentDirectory,strErrorLogFile;
	if(::GetCurrentDirectory(_MAX_PATH,strCurrentDirectory.GetBuffer(_MAX_PATH)))
	{
		strCurrentDirectory.ReleaseBuffer();// ReleaseBuffer before any other call to CString method
		strCurrentDirectory.MakeLower();

		int nBackSlashPos = strCurrentDirectory.ReverseFind(_T('\\'));
		int nPathLength = strCurrentDirectory.GetLength();
		if(nBackSlashPos != nPathLength-1)
			strCurrentDirectory += _T("\\");
		strCurrentDirectory += FM_ERROR_LOG_FOLDER;

		//record log by process
#ifdef MULTIFMWIN
		CString cstrTemp;
		DWORD pid = GetCurrentProcessId();
		cstrTemp.Format(_T("%d"),pid);
		strCurrentDirectory += "\\";
		strCurrentDirectory += cstrTemp;
#endif

		if(!::PathFileExists(strCurrentDirectory) && SHCreateDirectoryEx(NULL,strCurrentDirectory,NULL) != ERROR_SUCCESS)
		{
			ASSERT(FALSE);
			CString strTemp;
			return strTemp;
		}
		strCurrentDirectory += _T("\\");
	}

	SYSTEMTIME st;
	GetLocalTime(&st);
	if(iErrorType == 1)
	{	
		strErrorLogFile.Format(_T("%sFMError_%04d%02d%02d_%02d%02d%02d.dmp"), 
			strCurrentDirectory, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
	}
	else
	{
		strErrorLogFile.Format(_T("%sFMLog_%04d%02d%02d.txt"), strCurrentDirectory, st.wYear, st.wMonth, st.wDay);
	}
	return strErrorLogFile;
}

void CFMErrorLog::ReleaseAssert(bool bNotLog, CString strFile, int nLine, CString strFunction, CString strErrMsg, int nAssertLevel)
{
	if (!bNotLog)
	{
		if(m_bShowDefaultInfo)
			WriteDefaultInfo();

		if (nAssertLevel<m_nAssertLevel)
		{
			CString strLevel;
			switch(nAssertLevel)
			{
			case eAssertLevel_Fatal:
				strLevel = _T("Fatal");
				break;
			case eAssertLevel_Error:
				strLevel = _T("Error");
				break;
			case eAssertLevel_Warn:
				strLevel = _T("Warn");
				break;
			case eAssertLevel_Info:
				strLevel = _T("Info");
				break;
			case eAssertLevel_Debug:
				strLevel = _T("Debug");
				break;
			default:
				strLevel = _T("Unknown");
				break;
			}

			switch(m_nAssertType)
			{
			case eTextLog:
				WriteAssertAsTxt(strErrMsg, strLevel, strFile, nLine, strFunction);
				break;
			case eDumpLog:
				WriteAssertAsDump();
				break;
			default:
				WriteAssertAsTxt(strErrMsg, strLevel, strFile, nLine, strFunction);
				break;
			}
		}
	}	
}

void CFMErrorLog::ReleaseAssert( int nNotLog, CString strFile, int nLine, CString strFunction, CString strErrMsg/*=_T("")*/, int nErrorLogLevel/*=0*/ )
{
	ReleaseAssert(nNotLog!=0, strFile, nLine, strFunction, strErrMsg, nErrorLogLevel);
}

void CFMErrorLog::ReleaseAssert( UINT nNotLog, CString strFile, int nLine, CString strFunction, CString strErrMsg/*=_T("")*/, int nErrorLogLevel/*=0*/ )
{
	ReleaseAssert(nNotLog!=0, strFile, nLine, strFunction, strErrMsg, nErrorLogLevel);
}

void CFMErrorLog::ReleaseAssert( ULONG_PTR nNotLog, CString strFile, int nLine, CString strFunction, CString strErrMsg/*=_T("")*/, int nErrorLogLevel/*=0*/ )
{
	ReleaseAssert(nNotLog!=0, strFile, nLine, strFunction, strErrMsg, nErrorLogLevel);
}

void CFMErrorLog::ReleaseAssert( void *nNotLog, CString strFile, int nLine, CString strFunction, CString strErrMsg/*=_T("")*/, int nErrorLogLevel/*=0*/ )
{
	ReleaseAssert(nNotLog!=0, strFile, nLine, strFunction, strErrMsg, nErrorLogLevel);
}

void CFMErrorLog::ReleaseAssert( const void *nNotLog, CString strFile, int nLine, CString strFunction, CString strErrMsg/*=_T("")*/, int nErrorLogLevel/*=0*/ )
{
	ReleaseAssert(nNotLog!=0, strFile, nLine, strFunction, strErrMsg, nErrorLogLevel);
}

void CFMErrorLog::Log(BOOL bNotLog, CString strFile, int nLine, CString strFunction, CString strErrMsg/*=_T("")*/, int nErrorLogLevel/*=0*/ )
{
	if (!bNotLog)
	{
		if (nErrorLogLevel<m_nAssertLevel)
		{		
			ReleaseAssert(bNotLog, strFile, nLine, strFunction, strErrMsg, nErrorLogLevel);
		}
		else
		{
			// 			if (!strErrMsg.IsEmpty())
			// 			{
			// 				TRACE(_T("============[FM_TRACE:]"));
			// 				TRACE(strErrMsg);
			// 				TRACE(_T("============\n"));
			// 			}
		}
	}
}

void CFMErrorLog::GetAssertLevel()
{
	//FM_GETVARENVINI_INT_DEFAULT(m_nAssertLevel,	_T("RDM"),	_T("ErrorLogLevel"), 3);	
	//FM_GETVARENVINI_INT_DEFAULT(m_nAssertType,	_T("RDM"),	_T("ErrorLogType"),	0);	
}

void CFMErrorLog::WriteAssertAsTxt( CString strErrMsg, CString strLevel, CString strFile, int nLine, CString strFunction )
{
	CString strErrorLogFile;
	strErrorLogFile = FMGetCurrentDirFile(m_nAssertType);

	CStdioFile oFile;
	CFileException ex;
	int iCounter=0;//count for loop to avoid dead loop
	do 
	{
		if(oFile.Open(strErrorLogFile, CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate|CFile::shareDenyWrite,&ex))
		{
			oFile.SeekToEnd();
			SYSTEMTIME st;
			GetLocalTime(&st);
			CString strErrorLog;
			if (strErrMsg.IsEmpty())
			{
				strErrorLog.Format(_T("[%s]\t%02d:%02d:%02d\tFILE:\t%s\\,\tLINE:\t%d,\tFUNCTION:\t%s\n"), 
					strLevel, st.wHour, st.wMinute, st.wSecond, strFile, nLine, strFunction);
			}
			else
			{
				strErrorLog.Format(_T("[%s]\t%02d:%02d:%02d\tFILE:\t%s\\,\tLINE:\t%d,\tFUNCTION:\t%s,\tMessage:\t%s\n"), 
					strLevel, st.wHour, st.wMinute, st.wSecond, strFile, nLine, strFunction, strErrMsg);
			}

			oFile.WriteString(strErrorLog);
			oFile.Close();
			break;
		}
		else
		{
			if (ex.m_cause==CFileException::sharingViolation)
			{
				if (++iCounter > 100)
				{
					break;//if this thread run 100 times then exit
				}

				Sleep(20);
				continue;
			} 
			else
			{
				break;
			}
		}				
	}while(true);	
}

void CFMErrorLog::WriteAssertAsDump()
{
	//CString strErrorLogFile;
	//strErrorLogFile = FMGetCurrentDirFile(m_nAssertType);

	//// Create the file
	//HANDLE hFile = CreateFile(
	//	strErrorLogFile,
	//	GENERIC_WRITE,
	//	0,
	//	NULL,
	//	CREATE_ALWAYS,
	//	FILE_ATTRIBUTE_NORMAL,
	//	NULL);

	////
	//// Write the minidump to the file
	////
	//if (hFile)
	//{
	//	MINIDUMP_EXCEPTION_INFORMATION eInfo;
	//	eInfo.ThreadId = GetCurrentThreadId();
	//	eInfo.ExceptionPointers = NULL;
	//	eInfo.ClientPointers = FALSE;

	//	MINIDUMP_CALLBACK_INFORMATION cbMiniDump;
	//	cbMiniDump.CallbackRoutine = 0;
	//	cbMiniDump.CallbackParam = 0;

	//	MiniDumpWriteDump(
	//		GetCurrentProcess(),
	//		GetCurrentProcessId(),
	//		hFile,
	//		MiniDumpNormal,
	//		NULL,
	//		NULL,
	//		&cbMiniDump);
	//}

	//// Close file
	//CloseHandle(hFile);
}

void CFMErrorLog::WriteDefaultInfo()
{
	/*m_bShowDefaultInfo = FALSE;

	CString strErrorLogFile;
	strErrorLogFile = FMGetCurrentDirFile(m_nAssertType);

	CStdioFile oFile;
	if (oFile.Open(strErrorLogFile, CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate|CFile::shareDenyWrite))
	{
		oFile.SeekToEnd();
		CString strDefaultInfo;
		FMChar  zAppName[INFO_BUFFER_SIZE];
		CString strFMType = _T("Mensuel");

#ifdef SEMAINE
		strFMType = _T("Day/Week");
#endif
#ifdef PER13
		strFMType = _T("Periode");
#endif
		GetModuleFileName(NULL, zAppName, INFO_BUFFER_SIZE);

		CString strBitApp;
#ifdef _WIN64
		strBitApp.Format(FM_STATIC_LOCALIZED_MSG(ID_FMMSG_FM64BIT));
#else
		strBitApp.Format(FM_STATIC_LOCALIZED_MSG(ID_FMMSG_FM32BIT));
#endif
		CString strFin = FM_STATIC_LOCALIZED_MSG(ID_M_INFO_FIN);
		strDefaultInfo.Format(_T("\n%s\nBuid Number:\t\t\t= %s\nExecutable path:\t\t= %s\nVersion:\t\t\t= %s\t%s\n\n"), strFin,STRPRODUCTVER, zAppName, strFMType, strBitApp);

		oFile.WriteString(strDefaultInfo);
	}
	oFile.Close();*/
}